package cn.sc.summer.calculate.builder;

import cn.sc.summer.exception.exceptions.CommonException;
import cn.sc.summer.calculate.po.SystemInfoDTO;
import com.sun.management.OperatingSystemMXBean;
import lombok.extern.slf4j.Slf4j;
import oshi.SystemInfo;
import oshi.hardware.CentralProcessor;
import oshi.util.GlobalConfig;

import java.io.File;
import java.lang.management.ManagementFactory;
import java.lang.management.MemoryMXBean;
import java.lang.management.MemoryUsage;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.concurrent.TimeUnit;

/**
 * 类名：构造者实现类
 *
 * @author a-xin
 * @date 2023/9/5 14:47
 */
@Slf4j
public class SystemInfoBuilder extends SystemInfoService {

    private final SystemInfoDTO systemInfoDTO = new SystemInfoDTO();

    private static final BigDecimal ONE_MB = new BigDecimal(1024 * 1024 * 1024);

    private static final BigDecimal ONE_KB = new BigDecimal(1024 * 1024);

    /**
     * 构造系统基础信息
     */
    @Override
    protected void buildSystemInfo() {
        systemInfoDTO.setOsName(System.getProperty("os.name"));
        systemInfoDTO.setOsPid(ManagementFactory.getRuntimeMXBean().getName().split("@")[0]);
        systemInfoDTO.setOsUserHome(System.getProperty("user.home"));
        systemInfoDTO.setOsUserName(System.getProperty("user.name"));
    }

    /**
     * 构造java环境基础信息
     */
    @Override
    protected void buildJavaInfo() {
        systemInfoDTO.setJavaVersion(System.getProperty("java.version"));
        systemInfoDTO.setJavaHome(System.getProperty("java.home"));
    }

    /**
     * 构造jvm基础信息
     */
    @Override
    protected void buildJvmInfo() {
        // 椎内存使用情况
        MemoryMXBean memoryMXBean = ManagementFactory.getMemoryMXBean();
        MemoryUsage memoryUsage = memoryMXBean.getHeapMemoryUsage();
        BigDecimal totalJVMMemorySize = new BigDecimal(memoryUsage.getInit()).divide(ONE_KB, 2, RoundingMode.HALF_UP);
        systemInfoDTO.setJvmMemoryTotal(totalJVMMemorySize.toString());
        BigDecimal maxJVMMemorySize = new BigDecimal(memoryUsage.getMax()).divide(ONE_KB, 2, RoundingMode.HALF_UP);
        systemInfoDTO.setJvmMemoryMaxUse(maxJVMMemorySize.toString());
        BigDecimal usedJVMMemorySize = new BigDecimal(memoryUsage.getUsed()).divide(ONE_KB, 2, RoundingMode.HALF_UP);
        systemInfoDTO.setJvmMemoryUsed(usedJVMMemorySize.toString());
    }

    /**
     * 构造物理内存基础信息
     */
    @Override
    protected void buildPhysicalMemoryInfo() {
        OperatingSystemMXBean osmxb = (OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean();
        BigDecimal totalMemorySize = new BigDecimal(osmxb.getTotalPhysicalMemorySize()).divide(ONE_MB, 2, RoundingMode.HALF_UP);
        systemInfoDTO.setPhysicalMemoryTotal(totalMemorySize.toString());

        BigDecimal freePhysicalMemorySize = new BigDecimal(osmxb.getFreePhysicalMemorySize()).divide(ONE_MB, 2, RoundingMode.HALF_UP);
        systemInfoDTO.setPhysicalMemoryFree(freePhysicalMemorySize.toString());
    }

    /**
     * 构造cpu基础信息
     */
    @Override
    protected void buildCpuInfo() {
        SystemInfo systemInfo = new SystemInfo();
        GlobalConfig.set(GlobalConfig.OSHI_OS_WINDOWS_CPU_UTILITY, true);
        CentralProcessor processor = systemInfo.getHardware().getProcessor();
        long[] prevTicks = processor.getSystemCpuLoadTicks();
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (Exception e) {
            throw new CommonException(e.getMessage());
        }
        long[] ticks = processor.getSystemCpuLoadTicks();
        long nice = ticks[CentralProcessor.TickType.NICE.getIndex()] - prevTicks[CentralProcessor.TickType.NICE.getIndex()];
        long irq = ticks[CentralProcessor.TickType.IRQ.getIndex()] - prevTicks[CentralProcessor.TickType.IRQ.getIndex()];
        long softirq = ticks[CentralProcessor.TickType.SOFTIRQ.getIndex()] - prevTicks[CentralProcessor.TickType.SOFTIRQ.getIndex()];
        long steal = ticks[CentralProcessor.TickType.STEAL.getIndex()] - prevTicks[CentralProcessor.TickType.STEAL.getIndex()];
        long cSys = ticks[CentralProcessor.TickType.SYSTEM.getIndex()] - prevTicks[CentralProcessor.TickType.SYSTEM.getIndex()];
        long user = ticks[CentralProcessor.TickType.USER.getIndex()] - prevTicks[CentralProcessor.TickType.USER.getIndex()];
        long iowait = ticks[CentralProcessor.TickType.IOWAIT.getIndex()] - prevTicks[CentralProcessor.TickType.IOWAIT.getIndex()];
        long idle = ticks[CentralProcessor.TickType.IDLE.getIndex()] - prevTicks[CentralProcessor.TickType.IDLE.getIndex()];

        BigDecimal totalCpu = new BigDecimal(user + nice + cSys + idle + iowait + irq + softirq + steal);
        CentralProcessor.ProcessorIdentifier processorIdentifier = processor.getProcessorIdentifier();
        systemInfoDTO.setCpuProcessorCount(String.valueOf(processor.getLogicalProcessorCount()));
        systemInfoDTO.setCpuName(processorIdentifier.getName());

        BigDecimal cpuSysUsed = new BigDecimal(cSys * 100).divide(totalCpu, 5, RoundingMode.HALF_UP);
        systemInfoDTO.setCpuSysUsed(cpuSysUsed.toString());

        BigDecimal cpuUserUsed = new BigDecimal(user * 10).divide(totalCpu, 5, RoundingMode.HALF_UP);
        systemInfoDTO.setCpuUserUsed(cpuUserUsed.toString());

        BigDecimal cpuWait = new BigDecimal(iowait * 100).divide(totalCpu, 2, RoundingMode.HALF_UP);
        systemInfoDTO.setCpuWait(cpuWait.toString());

        BigDecimal cpuFree = new BigDecimal(idle * 100).divide(totalCpu, 5, RoundingMode.HALF_UP);
        systemInfoDTO.setCpuFree(cpuFree.toString());

        long cpuUtilization = user + nice + cSys + iowait + irq + softirq + steal;
        BigDecimal cpuUsed = new BigDecimal(cpuUtilization * 100).divide(totalCpu, 5, RoundingMode.HALF_UP);
        systemInfoDTO.setCpuUsed(cpuUsed.toString());
    }

    /**
     * 构造储存空间基础信息
     */
    @Override
    protected void buildSpaceInfo() {
        // 磁盘使用情况
        BigDecimal totalSpace = BigDecimal.ZERO;
        BigDecimal freeSpace = BigDecimal.ZERO;
        BigDecimal usableSpace = BigDecimal.ZERO;
        File[] files = File.listRoots();
        for (File file : files) {
            totalSpace = totalSpace.add(new BigDecimal(file.getTotalSpace()).divide(ONE_MB, 2, RoundingMode.HALF_UP));
            freeSpace = freeSpace.add(new BigDecimal(file.getFreeSpace()).divide(ONE_MB, 2, RoundingMode.HALF_UP));
            usableSpace = usableSpace.add(new BigDecimal(file.getUsableSpace()).divide(ONE_MB, 2, RoundingMode.HALF_UP));
        }
        systemInfoDTO.setSpaceTotal(totalSpace.toString());
        systemInfoDTO.setSpaceFree(freeSpace.toString());
        systemInfoDTO.setSpaceUsable(usableSpace.toString());
    }

    /**
     * 最终构造返回数据
     *
     * @return 系统基础信息实体类
     */
    @Override
    protected SystemInfoDTO build() {
        return systemInfoDTO;
    }

}
